home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / SMTPSERV.C < prev    next >
Text File  |  1993-07-22  |  10KB  |  441 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  * enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include "global.h"
  7. #include "config.h"
  8. #include "mbuf.h"
  9. #include "cmdparse.h"
  10. #include "socket.h"
  11. #include "smtp.h"
  12. #include "files.h"
  13. #include "bbs.h"
  14.  
  15. #ifdef NNTP
  16. #include "nntp.h"
  17. #endif
  18.  
  19. #ifdef LZW
  20. #include "lzw.h"
  21. #endif
  22.  
  23.  
  24. /* Reply messages */
  25. #ifdef LZW
  26. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN XLZW\n214 End\n";
  27. #else
  28. static char Help[] = "214-Commands:\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET EXPN\n214 End\n";
  29. #endif
  30. static char SmtpBanner[]    = "220 %s SMTP %s ready at %s";
  31. static char Closing[]        = "221 %s Closing\n";
  32. static char Ok[]            = "250 Ok\n";
  33. static char Reset[]            = "250 Reset state\n";
  34. static char Sent[]            = "250 Sent\n";
  35. static char Ourname[]        = "250 Hello %s, pleased to meet you\n";
  36. #ifdef LZW
  37. static char LZWOk[]            = "252 LZW Ok\n";
  38. #endif
  39. static char Enter[]            = "354 Enter mail, end with .\n";
  40. static char Ioerr[]            = "452 Temp file write error\n";
  41. static char Badcmd[]        = "500 Command unrecognized\n";
  42. static char Syntax[]        = "501 Syntax error\n";
  43. static char Needrcpt[]        = "503 Need RCPT (recipient)\n";
  44. static char Unknownaddr[]    = "550 <%s> address unknown\n";
  45. static char Noalias[]        = "550 No alias for <%s>\n";
  46.  
  47.  
  48. /* Read the rewrite file for lines where the first word is a regular
  49.  * expression and the second word are rewriting rules.
  50.  * The special character '$' followed by a digit denotes the string that
  51.  * matched a '*' character.
  52.  * The '*' characters are numbered from 1 to 9.
  53.  *
  54.  * Example: the line "*@*.* $2@$1.ampr.org" would rewrite the address
  55.  * "foo@bar.xxx" to "bar@foo.ampr.org".
  56.  *
  57.  * $H is replaced by our hostname, and $$ is an escaped $ character.
  58.  * If the third word on the line has an 'r' character in it, the function
  59.  * will recurse with the new address.
  60.  */
  61. static char * near
  62. rewrite_address(char *addr)
  63. {
  64.     FILE *fp;
  65.  
  66.     if((fp = Fopen(Rewritefile,READ_TEXT,0,0)) != NULLFILE) {
  67.         char *argv[10], buf[LINELEN], *cp, *cp2, *retstr = NULLCHAR;
  68.         int cnt;
  69.  
  70.         memset(argv,0,10 * sizeof(char *));
  71.  
  72.         while(fgets(buf,LINELEN,fp) != NULLCHAR) {
  73.             if(*buf == '#') {
  74.                 continue;
  75.             }
  76.             if((cp = strchr(buf,' ')) == NULLCHAR) {     /* get the first word */
  77.                 if((cp = strchr(buf,'\t')) == NULLCHAR) {
  78.                     continue;
  79.                 }
  80.             }
  81.             *cp = '\0';
  82.  
  83.             if((cp2 = strchr(buf,'\t')) != NULLCHAR) {
  84.                 *cp = ' ';
  85.                 cp = cp2;
  86.                 *cp = '\0';
  87.             }
  88.             if(!wildmat(addr,buf,argv)) {
  89.                 continue;        /* no match */
  90.             }
  91.             rip(++cp);
  92.             retstr = mxallocw(LINELEN);
  93.             cp2 = retstr;
  94.  
  95.             while(*cp != '\0' && *cp != ' ' && *cp != '\t') {
  96.                 if(*cp == '$') {
  97.                     if(isdigit(*(++cp))) {
  98.                         if(argv[*cp - '0'-1] != '\0') {
  99.                             strcat(cp2,argv[*cp - '0' - 1]);
  100.                         }
  101.                     }
  102.                     if(*cp == 'h' || *cp == 'H') {         /* Our hostname */
  103.                         strcat(cp2,Hostname);
  104.                     }
  105.                     if(*cp == '$') {                    /* Escaped $ character */
  106.                         strcat(cp2,"$");
  107.                     }
  108.                     cp2 = retstr + strlen(retstr);
  109.                     cp++;
  110.                 } else {
  111.                     *cp2++ = *cp++;
  112.                 }
  113.             }
  114.             for(cnt = 0; argv[cnt] != NULLCHAR; cnt++) {
  115.                 xfree(argv[cnt]);
  116.             }
  117.             Fclose(fp);
  118.  
  119.             /* If there remains an 'r' character on the line, repeat
  120.              * everything by recursing.
  121.              */
  122.             if(strchr(cp,'r') != NULLCHAR || strchr(cp,'R') != NULLCHAR) {
  123.                 if((cp2 = rewrite_address(retstr)) != NULLCHAR) {
  124.                     xfree(retstr);
  125.                     return cp2;
  126.                 }
  127.             }
  128.             Fclose(fp);
  129.             return retstr;
  130.         }
  131.         Fclose(fp);
  132.     }
  133.     return NULLCHAR;
  134. }
  135.  
  136. /* ------------------------ SMTP server subcmds --------------------------- */
  137.  
  138. static void near
  139. data_command(struct smtpserv *mp)
  140. {
  141.     if(mp->to == NULLLIST) {
  142.         usputs(mp->s,Needrcpt);
  143.         return;
  144.     } else if((mp->data = Tmpfile(0,1)) != NULLFILE) {
  145.         usputs(mp->s,Enter);
  146.  
  147.         /* Add timestamp; rfc822_date adds newline */
  148.         fputs(Hdrs[RECEIVED],mp->data);
  149.  
  150.         if(mp->system != NULLCHAR) {
  151.             fprintf(mp->data,"from %s ",mp->system);
  152.         }
  153.         fprintf(mp->data,"by %s with SMTP\n\tid AA%ld; %s",
  154.             Hostname,get_msgid(),rfc822_date(&currtime));
  155.  
  156.         for( ; ;) {
  157.             if(recvline(mp->s,mp->buf,LINELEN) == -1) {
  158.                 goto quit1;
  159.             }
  160.             rip(mp->buf);
  161.  
  162.             /* check for end of message ie a . or escaped .. */
  163.             if(*mp->buf == '.') {
  164.                 if(*++mp->buf == '\0') {
  165.                     /* Also sends appropriate response */
  166.                     usputs(mp->s,(mailit(mp->data,mp->from,mp->to) != 0) ? Ioerr : Sent);
  167.  
  168.                     goto quit1;
  169.                 } else if (!(*mp->buf == '.' && *(mp->buf + 1) == '\0')) {
  170.                     mp->buf--;
  171.                 }
  172.             }
  173.             /* for UNIX mail compatiblity */
  174.             if(strncmp(mp->buf,"From ",5) == 0) {
  175.                 fputc('>',mp->data);
  176.             }
  177.             /* Append to data file */
  178.             if(fprintf(mp->data,"%s\n",mp->buf) == EOF) {
  179.                 goto quit;
  180.             }
  181.         }
  182.     }
  183. quit:
  184.     usputs(mp->s,Ioerr);
  185. quit1:
  186.     Fclose(mp->data);
  187.     mp->data = NULLFILE;
  188.     del_list(mp->to);
  189.     mp->to = NULLLIST;
  190. }
  191.  
  192. static void near
  193. expn_command(struct smtpserv *mp)
  194. {
  195.     char *newaddr = NULLCHAR;
  196.     struct list *ap, *list = NULLLIST;
  197.  
  198.     if(*mp->buf == '\0') {
  199.         usputs(mp->s,Syntax);
  200.         return;
  201.     }
  202.     /* rewrite address if possible */
  203.     if((newaddr = rewrite_address(mp->buf)) != NULLCHAR) {
  204.         if(strcmp(newaddr,mp->buf) != 0) {
  205.             strcpy(mp->buf,newaddr);
  206.         }
  207.     }
  208.     expandalias(&list,mp->buf);
  209.  
  210.     if(strcmp(list->val,mp->buf) == 0 && list->next == NULLLIST) {
  211.         if(newaddr == NULLCHAR) {
  212.             usprintf(mp->s,Noalias,mp->buf);
  213.             del_list(list);
  214.             return;
  215.         }
  216.     }
  217.     if(newaddr != NULLCHAR) {
  218.         xfree(newaddr);
  219.     }
  220.     ap = list;
  221.  
  222.     while(ap->next != NULLLIST) {
  223.         usprintf(mp->s,"250-%s\n",ap->val);
  224.         ap = ap->next;
  225.     }
  226.     usprintf(mp->s,"250 %s\n",ap->val);
  227.  
  228.     del_list(list);
  229. }
  230.  
  231. static void near
  232. helo_command(struct smtpserv *mp)
  233. {
  234.     if(mp->system != NULLCHAR) {
  235.         xfree(mp->system);
  236.     }
  237.     mp->system = strxdup(mp->buf);
  238.     usprintf(mp->s,Ourname,mp->system);
  239. }
  240.  
  241. static void near
  242. help_command(struct smtpserv *mp)
  243. {
  244.     usputs(mp->s,Help);
  245. }
  246.  
  247. static void near
  248. mail_command(struct smtpserv *mp)
  249. {
  250.     char *cp;
  251.  
  252.     if((cp = getname(mp->buf)) == NULLCHAR) {
  253.         usputs(mp->s,Syntax);
  254.         return;
  255.     }
  256.     if(mp->from != NULLCHAR) {
  257.         xfree(mp->from);
  258.     }
  259.     mp->from = strxdup(cp);
  260.     mp->states = PROMPT;
  261. }
  262.  
  263. static void near
  264. noop_command(struct smtpserv *mp)
  265. {
  266.     mp->states = PROMPT;
  267. }
  268.  
  269. static void near
  270. quit_command(struct smtpserv *mp)
  271. {
  272.     usprintf(mp->s,Closing,Hostname);
  273.     mp->states = CLOSED;
  274. }
  275.  
  276. static void near
  277. rcpt_command(struct smtpserv *mp)
  278. {
  279.     char *cp, *newaddr = NULLCHAR;
  280.     int address_type;
  281.  
  282.     if((cp = getname(mp->buf)) == NULLCHAR) {
  283.         usputs(mp->s,Syntax);
  284.         return;
  285.     }
  286.     /* rewrite address if possible */
  287.     if((newaddr = rewrite_address(cp)) != NULLCHAR) {
  288.         cp = newaddr;
  289.     }
  290.     /* check if address is ok */
  291.     if((address_type = validate_address(cp)) == BADADDR) {
  292.         usprintf(mp->s,Unknownaddr,cp);
  293.         return;
  294.     }
  295.     /* if a local address check for an alias */
  296.     if(address_type == LOCAL) {
  297.         expandalias(&mp->to,cp);
  298.     } else {
  299.         /* a remote address is added to the list */
  300.         addlist(&mp->to,cp,address_type);
  301.     }
  302.     if(newaddr != NULLCHAR) {
  303.         xfree(newaddr);
  304.     }
  305.     mp->states = PROMPT;
  306. }
  307.  
  308. static void near
  309. rset_command(struct smtpserv *mp)
  310. {
  311.     usputs(mp->s,Reset);
  312.     del_list(mp->to);
  313.     mp->to = NULLLIST;
  314. }
  315.  
  316. #ifdef LZW
  317. static void near
  318. xlzw_command(struct smtpserv *mp)
  319. {
  320.     if(Smtplzw) {
  321.         int lzwbits = 99;
  322.         int lzwmode = -1;
  323.  
  324.         sscanf(mp->buf,"%d %d",&lzwbits,&lzwmode);
  325.  
  326.         if(lzwbits > lzwmode && 9 < lzwbits && lzwbits < 17
  327.           && (lzwmode == 0 || lzwmode == 1)) {
  328.             usputs(mp->s,LZWOk);
  329.             lzwinit(mp->s,lzwbits,lzwmode);
  330.             return;
  331.         }
  332.     }
  333.     usputs(mp->s,Badcmd);
  334. }
  335. #endif
  336.  
  337. void
  338. smtpserv(int s,void *unused,void *p)
  339. {
  340.     struct smtpserv *mp;
  341.     char *cp, *cp1;
  342.     int arglen;
  343.  
  344.     static struct cmdtable {
  345.         char *name;
  346.         void near (*func) __ARGS((struct smtpserv *mp));
  347.         int states;
  348.     } cmdtable[] = {
  349.         {"DATA",        data_command,    0},
  350.         {"EXPN",        expn_command,    0},
  351.         {"HELO",        helo_command,    0},
  352.         {"HELP",        help_command,    0},
  353.         {"MAIL FROM:",    mail_command,    0},
  354.         {"NOOP",        noop_command,    0},
  355.         {"QUIT",        quit_command,    0},
  356.         {"RCPT TO:",    rcpt_command,    0},
  357.         {"RSET",        rset_command,    0},
  358. #ifdef LZW
  359.         {"XLZW",        xlzw_command,    0},
  360. #endif
  361.         {0, 0, 0},
  362.     };
  363.     struct cmdtable *cmdp;
  364.  
  365.     sockmode(s,SOCK_ASCII);
  366.     sockowner(s,Curproc);        /* We own it now */
  367.  
  368.     mp = mxallocw(sizeof(struct smtpserv));
  369.     mp->buf = mxallocw(LINELEN);
  370.  
  371.     mp->s = s;
  372.  
  373.     usprintf(mp->s,SmtpBanner,Hostname,Version,ctime(&currtime));
  374.  
  375.     log(mp->s,9983,"SMTP open");
  376.  
  377.     for( ; ;) {
  378. loop:
  379.         if(mp->states == CLOSED) {
  380.             break;
  381.         }
  382.         if(mp->states == PROMPT) {
  383.             usputs(mp->s,Ok);
  384.         }
  385.         mp->states = OK;
  386.  
  387.         if(recvline(mp->s,mp->buf,LINELEN) <= 0) {
  388.             /* He closed on us */
  389.             break;
  390.         }
  391.         rip(mp->buf);
  392.  
  393.         for(cp = mp->buf; *cp && isspace(*cp); cp++) ;
  394.  
  395.         for(cp1 = cp, arglen = 0; *cp1 && *cp1 != ':'; cp1++, arglen++) {
  396.             if(isspace(*cp1) && !(strstr(cp1 + 1,":<"))) {
  397.                 break;
  398.             }
  399.         }
  400.         if(arglen) {
  401.             for(cmdp = cmdtable; cmdp->name; cmdp++) {
  402.                 if(strnicmp(cmdp->name,cp,arglen) == 0) {
  403.                     char *line, *cp2;
  404.  
  405.                     for(cp2 = cp1; *cp2 && isspace(*cp2); cp2++) ;
  406.  
  407.                     line = strxdup(cp2);
  408.                     strcpy(mp->buf,line);
  409.                     xfree(line);
  410.                     (*cmdp->func)(mp);
  411.                     goto loop;
  412.                 }
  413.             }
  414.         }
  415.         /* Can't be a legal command */
  416.         usputs(mp->s,Badcmd);
  417.     }
  418.     log(mp->s,9983,"SMTP close");
  419.  
  420.     xfree(mp->buf);
  421.  
  422.     if(mp->system != NULLCHAR) {
  423.         xfree(mp->system);
  424.     }
  425.     if(mp->from != NULLCHAR) {
  426.         xfree(mp->from);
  427.     }
  428.     if(mp->data != NULLFILE) {
  429.         Fclose(mp->data);
  430.     }
  431.     if(mp->to != NULLLIST) {
  432.         del_list(mp->to);
  433.     }
  434.     close_s(s);
  435.  
  436.     xfree(mp);
  437.  
  438.     smtptick(NULL);            /* start SMTP daemon immediately */
  439. }
  440.  
  441.